/* manages the syscall interrupts. It uses a code to figure out what it has to do, performs the request work and returns the result */

#include "syscall.h"

/* The parameters might not be defined for some system calls. Use them carefully. */
void dispatch_syscall(){
  // we get a pointer to the saved registers of the caller. We will use it to fetch the information needed to do the call */
  int32_t still_here = 1;
  int32_t result = 0; 
  registers_t* regs = pcb_get_registers(caller);
  int32_t syscall_code = regs->v_reg[0];
  switch(syscall_code){
  case FOURCHETTE:
    result = create_process(regs->a_reg[0],(char*)regs->a_reg[1],pcb_get_pid(caller), (int32_t*)regs->a_reg[2], 1);
    break;
  case TUER:
    result = remove_process(regs->a_reg[0],regs->a_reg[1]);
    if(result == SUCCESS && regs->a_reg[0] == pcb_get_pid(caller))
      //the caller killed himself
      still_here = 0;
    break;
  case QUITTER:
    //quitter affects only the caller
    result = remove_process_pcb(caller,regs->a_reg[0]);
    if(result == SUCCESS)
      still_here = 0; //the caller is already gone
    break;
  case OBTENIR_PROGRAMME:
    result = (int32_t)get_program(regs->a_reg[0], pcb_get_pid(caller));
    break;
  case OBTENIR_PID:
    result = pcb_get_pid(caller);
    break;
  case OBTENIR_PRIORITE:
    result = get_priority(regs->a_reg[0]);
    break;
  case OBTENIR_ETAT:
    result = get_state(regs->a_reg[0]);
    break;
  case OBTENIR_PARENT:
    result = get_parent(regs->a_reg[0]);
    break;
  case BLOQUER:
    result = block(regs->a_reg[0]);
    break;
  case REVEILLER:
    result = wake_up(regs->a_reg[0]);
    break;
  case ATTENDRE:
    result = wait(regs->a_reg[0],(int32_t*)regs->a_reg[1]);
    break;
  case RETARDER:
    result = delay(regs->a_reg[0], regs->a_reg[1]);
    break;
  case CHANGER_PRIORITE:
    result = change_priority(regs->a_reg[0], regs->a_reg[1]);
    break;
  case LIRE:
    result = read_string((char*)regs->a_reg[0],regs->a_reg[1]);
    break;
  case ECRIRE:
    result = print_string((char*)regs->a_reg[0]);
    break;
  case ECRIRE_LCD:
    result = print_lcd((char*)regs->a_reg[0]);
    break;
  case ENVOYER_ENTIER:
    result = send_integer(regs->a_reg[0],regs->a_reg[1],regs->a_reg[2]);
    break;
  case ENVOYER_CHAINE:
    result = send_string(regs->a_reg[0],(char*)regs->a_reg[1],regs->a_reg[2]);
    break;
  case RECEVOIR_PREMIER:
    result = receive_first((message**)regs->a_reg[0]);
    break;
  case RECEVOIR_PRIORITE:
    result = receive_priority(regs->a_reg[0],(message**)regs->a_reg[1]);
    break;
  case RECEVOIR_DE:
    result = receive_from(regs->a_reg[0],(message**)regs->a_reg[1]);
    break;
  case RECEVOIR_PREMIER_DELAI:
    result = receive_first_timeout((message**)regs->a_reg[0],regs->a_reg[1]);
    break;
  case RECEVOIR_PRIORITE_DELAI:
    result = receive_priority_timeout(regs->a_reg[0],(message**)regs->a_reg[1],regs->a_reg[2]);
    break;
  case RECEVOIR_DE_DELAI:
    result = receive_from_timeout(regs->a_reg[0],(message**)regs->a_reg[1],regs->a_reg[2]);
    break;
  case OBTENIR_NOMBRE_MESSAGES:
    result = get_number_messages(caller);
    break;
  case SUPERVISER:
    result = register_supervisor(caller, regs->a_reg[0]);
    break;
  case ALLOUER:
    result = (int32_t)malloc(regs->a_reg[0],pcb_get_pid(caller));
    break;
  case LIBERER:
    result = free((void*)regs->a_reg[0], pcb_get_pid(caller));
    break;
  case STOPPER_SUPERVISION:
    result = stop_supervision(caller, regs->a_reg[0]);
    break;
  case ENVOYER_INFORMATIONS_PROCESSUS:
    result = send_process_information(regs->a_reg[0],regs->a_reg[1]);
    break;
  case LIBERER_MESSAGE:
    result = free_message((message*)regs->a_reg[0],pcb_get_pid(caller));
    break;
  case OBTENIR_TOUS_PID:
    result = (int32_t)get_all_pid((int32_t*)regs->a_reg[0], pcb_get_pid(caller));
    break;
  case OBTENIR_PROGRAMME_PAR_ID:
    result = (int32_t)get_program_name(regs->a_reg[0], pcb_get_pid(caller));
    break;
  case OBTENIR_PROGRAMME_AIDE:
    result = (int32_t)get_program_help((char*)regs->a_reg[0], pcb_get_pid(caller));
    break;
  default:
    ;
  }
  //saves the return code into the caller's PCB 
  if(still_here)
    regs->v_reg[0] = result;
}
